package org.peacewing.compiler;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;

import org.peacewing.core.ApplicationContextXml;
import org.peacewing.core.SpringMVCFacade;
import org.peacewing.domain.Domain;
import org.peacewing.domain.Dropdown;
import org.peacewing.domain.Field;
import org.peacewing.domain.Pair;
import org.peacewing.domain.Prism;
import org.peacewing.domain.Project;
import org.peacewing.domain.ValidateInfo;
import org.peacewing.exception.ValidateException;
import org.peacewing.generator.DBDefinitionGenerator;
import org.peacewing.generator.MysqlDBDefinitionGenerator;
import org.peacewing.oracle.core.OracleDomainDecorator;
import org.peacewing.oracle.core.OraclePrism;
import org.peacewing.oracle.generator.Oracle11gDBDefinitionGenerator;
import org.peacewing.utils.DomainUtil;
import org.peacewing.utils.StringUtil;

public class SGSCompiler {
	protected final static String [] forbiddenwords = {"abstract", "assert","boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum","extends", "final", "finally", "float", "for", "if",

	                                      "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super","switch",

	                                      "synchronized", "this", "throw", "throws","transient", "try", "void", "volatile", "while","byValue", "cast", "false", "future", "generic", "inner", "operator", "outer", "rest", "true", "var","goto","const","null"};
	
	protected final static String [] sqlKeyWords = {"alter","and","as","asc","between","by","count","create","delete","desc","distinct","drop","from","group","having","in","insert","into","is","join","like","not","on","or","order","select","set","table","union","update","values","where","limit",
			"bool","boolean","bit","blob","enum","long","longblob","longtext","medium","mediumblob","mediumint","mediumtext","time","timestamp","tinyblob","tinyint","tinytext","text","bigint","int","int1","int2","int3","int4","int8","integer","float","float4","float8","double","char","varbinary","varchar","varcharacter","precision","real","date","datetime","year","unsigned","signed","decimal","numeric",
			"false","true","null","unknown","date","time","timestamp"};
	
	public static boolean isSqlKeyword(String notion){
		for (String word: sqlKeyWords){
			if (word.equals(notion)) return true;
		}
		return false;
	}
	
	public static boolean isForbidden(String notion){
		for (String word: forbiddenwords){
			if (word.equals(notion)) return true;
		}
		return false;
	}
 
	public SGSCompiler() {}
	public static Project translate(String sgs,boolean ignoreWarning) throws ValidateException, Exception {
		try {
			if (containsRoundAndSquareBrackets(sgs)){
				throw new ValidateException("源码中存在圆括号或方括号。");
			}
			List<String> notions = parseNotions(sgs);
			Project project = notionsToProject(notions,ignoreWarning);
			ValidateInfo info = basicValidateProject(project);
			project.setSgsSource(sgs);
			if (ignoreWarning|| info.getCompileWarnings().size()==0){
				return project;
			} else {
				ValidateException em = new ValidateException(info);
				throw em;
			}
		} catch (ValidateException e){
			ValidateInfo info = e.getValidateInfo();
			for (String s: info.getCompileErrors()){
				System.out.println(s);
			}
			throw e;
		}
	}
	
	public static List<String> parseNotions(String sgs){
		return SGSTokenizer.generateTokens(sgs);
	}
	
	public static Project notionsToProject(List<String> notions,boolean ignoreWarning) throws ValidateException, Exception {
		Project project;
		boolean headFinish = false;
		Stack<String> projectStack = new Stack<String>();
		DBDefinitionGenerator dbdg = new MysqlDBDefinitionGenerator();
		ApplicationContextXml axml = new ApplicationContextXml();
		int domainCount = countDomains(notions);
		for (int i=0; i < notions.size();i++) {
			if ("project".equals(notions.get(i))){
				project = new Project();
				if (!isKeyword(notions.get(i+1))){
					String mydbname0 = notions.get(i+1);
					project.setStandardName(mydbname0);
					project.setDbName(project.getStandardName());
					project.setTechnicalstack("smeu");
					dbdg.setDbName(mydbname0);
					axml.setDbname(mydbname0);
					if ("{".equals(notions.get(i+2))){
						projectStack.push("{");
						for (int j=i+3; j < notions.size();j++) {

						if ("packagetoken".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))&&!isKeyword(notions.get(j+2))) {
								String packagetoken = notions.get(j+2);
								project.setPackageToken(notions.get(j+2));
								axml.setPackageToken(packagetoken);
							}
							if (";".equals(notions.get(j+3))) j += 3;
						}
						
						if ("dbprefix".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))&&!isKeyword(notions.get(j+2))) project.setDbPrefix(notions.get(j+2));
							if (";".equals(notions.get(j+3))) j += 3;
						}
						
						if ("dbusername".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))) {
								String mydbusername = notions.get(j+2);
								project.setDbUsername(mydbusername);
								axml.setDbUsername(mydbusername);
							}
							if (";".equals(notions.get(j+3))) j += 3;
						}
						
						if ("dbpassword".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))) {
								String mydbpassword = notions.get(j+2);
								project.setDbPassword(mydbpassword);
								axml.setDbPassword(mydbpassword);
							}
							if (";".equals(notions.get(j+3))) j += 3;
						}
						

						if ("dbname".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))) {
								String mydbname = notions.get(j+2);
								project.setDbName(mydbname);
								dbdg.setDbName(mydbname);
								axml.setDbname(mydbname);
							}
							if (";".equals(notions.get(j+3))) j += 3;
						}
						
						if ("dbtype".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))) {
								String mydbtype = notions.get(j+2);
								project.setDbType(mydbtype);
								if (mydbtype!=null &&"oracle".equals(mydbtype)) {
									Oracle11gDBDefinitionGenerator dbdg2 = new Oracle11gDBDefinitionGenerator();
									if (dbdg.getDbName()!=null && !"".equals(dbdg.getDbName())) dbdg2.setDbName(dbdg.getDbName());
									dbdg = dbdg2;
								}
								dbdg.setDbType(mydbtype);
								axml.setDbType(mydbtype);
							}
							if (";".equals(notions.get(j+3))) j += 3;
						}
						
						
						if ("emptypassword".equals(notions.get(j))){
							project.setEmptypassword(true);
							axml.setEmptypassword(true);
							if (";".equals(notions.get(j+1))) j += 1;
						}
						
						if ("technicalstack".equals(notions.get(j))){
							if (":".equals(notions.get(j+1))&&!isKeyword(notions.get(j+2))) project.setTechnicalstack(notions.get(j+2));
							if (";".equals(notions.get(j+3))) j += 3;
						}
												
						if ("domain".equals(notions.get(j))|| "prism".equals(notions.get(j))){
							headFinish = true;
						}
						if (headFinish){						
							List<Domain> domainList = parseDomains(notions.subList(j, notions.size()),projectStack,project.getPackageToken());
							ValidateInfo info0 = validateDomains(domainList);
							if (info0!=null && info0.getCompileErrors()!=null && info0.getCompileErrors().size()>0) {
								throw new ValidateException(info0);
							}else if(info0!=null&& ignoreWarning==false&& info0.getCompileWarnings()!=null&&info0.getCompileWarnings().size()>0){
								throw new ValidateException(info0);
							}
							if (locateCallMagic(notions.subList(j, notions.size()))){
								return callMagic(project,domainList,dbdg,axml);
							}
							if (domainList != null && domainList.size() == domainCount){
								String dbPrefix = project.getDbPrefix();
								for (int m=0;m<domainList.size();m++){
									domainList.get(m).setDbPrefix(dbPrefix);
									domainList.get(m).decorateDomainWithLabels();
								}
								if (project.getPackageToken() == null || "".equals(project.getPackageToken())) {
									ValidateInfo info = new ValidateInfo();
									info.addCompileError("没有设置PackageToken！");
									throw new ValidateException(info);
								}
								if (project.getTechnicalstack() == null || "".equals(project.getTechnicalstack())||project.getTechnicalstack().equalsIgnoreCase("smeu")){
									decorateDropdowns(domainList);
									List<Prism> prismList = parsePrisms(notions.subList(j, notions.size()),projectStack,domainList,project.getPackageToken(),project.getDbType());
									TreeSet<SpringMVCFacade> myfacades = new TreeSet<SpringMVCFacade>();

									for (Prism p:prismList){
										myfacades.add(p.getFacade());
									}
									Project project2 = new Project(project.getStandardName(),project.getPackageToken(),project.getTechnicalstack(),
											project.getDbUsername(),project.getDbPassword(),project.isEmptypassword(),project.getDbName(),project.getDbType());
									project2.setPackageToken(project.getPackageToken());
									project2.setTechnicalstack(project.getTechnicalstack());
									project2.setDbPrefix(project.getDbPrefix());
									project2.setDbName(project.getDbName());
									project2.setDbPassword(project.getDbPassword());
									project2.setEmptypassword(project.isEmptypassword());
									project2.setDbType(project.getDbType());									
									project2.setDomains(domainList);								
									dbdg.setDomains(domainList);
						
									axml.setDomainList(domainList);
									axml.setDbname(project2.getDbName());
									axml.setDbPassword(project2.getDbPassword());
									axml.setEmptypassword(project2.isEmptypassword());;
									axml.setDbType(project2.getDbType());
									
									axml.setFacades(myfacades);
									if (project.isEmptypassword()) {
										axml.setDbPassword("");
										axml.setEmptypassword(true);
									}
									List<String> packageToScanList = new ArrayList<String>();
									packageToScanList.add(project.getPackageToken()+".domain");
									axml.setPackagesToScanList(packageToScanList);
									axml.setPutInsideSrcAndClasses(true);
								
									project2.addDBDefinitionGenerator(dbdg);									
									project2.setPrisms(prismList);
									project2.replaceConfigFile(axml);
									return project2;
								}
							}
						}
						
						}
					}			
				}			
			}
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("将片断缀合成项目错误。");
		throw new ValidateException(info);
	}
	
	public static List<Prism> parsePrisms(List<String> notions, Stack<String> projectStack, List<Domain> domainList, String packageToken) throws ValidateException,Exception{
		return parsePrisms(notions,projectStack,domainList,packageToken,"mysql");		
	}
	
	public static List<Prism> parsePrisms(List<String> notions, Stack<String> projectStack, List<Domain> domainList, String packageToken,String dbType) throws ValidateException,Exception{
		if ("".equals(dbType)||"mysql".equals(dbType)){
			List<Prism> list = new ArrayList<Prism>();
			Prism prism = new Prism();
			boolean prismStackjOverflow = false;
			Stack<String> prismStack = new Stack<String>();
			boolean started = false;
			int totalPrismCounts = countPrisms(notions);
			Set<Domain> projectDomainSet = new TreeSet<Domain>();
			projectDomainSet.addAll(domainList);
			
			for (int i=0; i < notions.size();i++) {
				if  (!"prism".equals(notions.get(i))) {
					notions.remove(i);
					i = i - 1;
				} else {
					break;
				}
			}
			
			for (int i = 0; i < notions.size(); i++){
	
				if ("prism".equals(notions.get(i))){
					prism = new Prism();
					if (!isKeyword(notions.get(i+1))){
						prism.setStandardName(notions.get(i+1));
					}
					if ("{".equals(notions.get(i+2))){
						prismStack.push("{");
						projectStack.push("{");
					}
					i= i +3;
				}
				
				if ("{".equals(notions.get(i))){
					if (!prismStackjOverflow){
						prismStack.push("{");
					}else{
						prismStackjOverflow = false;
					}
					projectStack.push("{");
				}
				
				if ("}".equals(notions.get(i))){
					if (!prismStack.empty()){
						prismStack.pop();
					} else {
						prismStackjOverflow = true;
					}
					projectStack.pop();
				}
						
				if (prismStack.empty()&&list.size() < totalPrismCounts){
					list.add(prism);
				}else if (prismStack.empty()&&list.size()== totalPrismCounts){
					for (Prism p:list){
						List<Pair> mtmSlaveNames = new ArrayList<Pair>();
						for (String str:p.getDomain().getManyToManySlaveNames()){
							mtmSlaveNames.add(new Pair(p.getDomain().getStandardName(),str));
						}
						p.setManyToManySlaveNames(mtmSlaveNames);
						p.setProjectDomains(projectDomainSet);
					}
					return list;
				}
				
				if ("prismdomain".equals(notions.get(i))){
					if (":".equals(notions.get(i+1))){
						if (!isKeyword(notions.get(i+2))){
							Domain d = findDomainFromListByStandardName(domainList, notions.get(i+2));
							d.decorateDomainWithLabels();
							if (d!=null) prism.setDomain(d);
							prism.setPackageToken(packageToken);
							prism.setProjectDomains(projectDomainSet);
							prism.generatePrismFromDomain();
							prism.expandPackageToken();
							i = i+2;
							started = true;
						}
					} 
				 }	
			 }				
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("解析棱柱错误。");
			throw new ValidateException(info);
		}
		else if ("oracle".equals(dbType)){
			List<Prism> list = new ArrayList<Prism>();
			OraclePrism prism = new OraclePrism();
			boolean prismStackjOverflow = false;
			Stack<String> prismStack = new Stack<String>();
			boolean started = false;
			int totalPrismCounts = countPrisms(notions);
			Set<Domain> projectDomainSet = new TreeSet<Domain>();
			projectDomainSet.addAll(domainList);
			
			for (int i=0; i < notions.size();i++) {
				if  (!"prism".equals(notions.get(i))) {
					notions.remove(i);
					i = i - 1;
				} else {
					break;
				}
			}
			
			for (int i = 0; i < notions.size(); i++){
	
				if ("prism".equals(notions.get(i))){
					prism = new OraclePrism();
					if (!isKeyword(notions.get(i+1))){
						prism.setStandardName(notions.get(i+1));
					}
					if ("{".equals(notions.get(i+2))){
						prismStack.push("{");
						projectStack.push("{");
					}
					i= i +3;
				}
				
				if ("{".equals(notions.get(i))){
					if (!prismStackjOverflow){
						prismStack.push("{");
					}else{
						prismStackjOverflow = false;
					}
					projectStack.push("{");
				}
				
				if ("}".equals(notions.get(i))){
					if (!prismStack.empty()){
						prismStack.pop();
					} else {
						prismStackjOverflow = true;
					}
					projectStack.pop();
				}
						
				if (prismStack.empty()&&list.size() < totalPrismCounts){
					list.add(prism);
				}else if (prismStack.empty()&&list.size()== totalPrismCounts){
					for (Prism p:list){
						p = (OraclePrism)p;
						List<Pair> mtmSlaveNames = new ArrayList<Pair>();
						for (String str:p.getDomain().getManyToManySlaveNames()){
							mtmSlaveNames.add(new Pair(p.getDomain().getStandardName(),str));
						}
						p.setManyToManySlaveNames(mtmSlaveNames);
						p.setProjectDomains(OracleDomainDecorator.decorateOracleDomainSet(projectDomainSet));
					}
					return list;
				}
				
				if ("prismdomain".equals(notions.get(i))){
					if (":".equals(notions.get(i+1))){
						if (!isKeyword(notions.get(i+2))){
							Domain d = findDomainFromListByStandardName(domainList, notions.get(i+2));
							d= OracleDomainDecorator.decorateOracleDomain(d);
							d.decorateDomainWithLabels();							
							if (d!=null) prism.setDomain(d);
							prism.setPackageToken(packageToken);
							prism.setProjectDomains(OracleDomainDecorator.decorateOracleDomainSet(projectDomainSet));
							prism.generatePrismFromDomain();
							prism.expandPackageToken();
							i = i+2;
							started = true;
						}
					} 
				 }	
			 }				
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("解析棱柱错误。");
			throw new ValidateException(info);
		}else{
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("未支持项目所用数据库。");
			throw new ValidateException(info);
		}
	}	

	public static  Domain findDomainFromListByStandardName(List<Domain> domainList, String standardName) throws ValidateException{
		for (Domain d:domainList){
			if (d.getStandardName().equals(standardName)) return d;
		}
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("在域对象列表找不到域对象"+standardName+"。");
		throw new ValidateException(info);
	}
	
	public static List<Domain> parseDomains(List<String> notions, Stack<String> projectStack, String packageToken) throws ValidateException{
		List<Domain> list = new ArrayList<Domain>();
		Domain domain = new Domain();
		boolean domainStackjOverflow = false;
		Stack<String> domainStack = new Stack<String>();
		int totalDomainCounts = countDomains(notions);		
		
		for (int i = 0; i < notions.size(); i++){
			if ("call".equals(notions.get(i))){
				if ("magic".equals(notions.get(i+1))&& ";".equals(notions.get(i+2))){
					for (Domain d:list) d.decorateDomainWithLabels();
					return list;
				}
			}	
			
			if ("domain".equals(notions.get(i))){
				domain = new Domain();
				domain.setPackageToken(packageToken);
				if (isForbidden(notions.get(i+1))){
					ValidateInfo info = new ValidateInfo();
					info.addCompileError("使用了被禁止的单词:"+notions.get(i+1));
					throw new ValidateException(info);
				}
				if (isSqlKeyword(notions.get(i+1))){
					ValidateInfo info = new ValidateInfo();
					info.addCompileError("使用了SQL关键字"+notions.get(i+1));
					throw new ValidateException(info);
				}
				if (!isKeyword(notions.get(i+1))){
					domain.setStandardName(notions.get(i+1));					
				}
				if ("{".equals(notions.get(i+2))){
					domainStack.push("{");
					projectStack.push("{");
				}
				i= i +3;
				//continue;
			}
			
			if ("{".equals(notions.get(i))){
				if (!domainStackjOverflow){
					domainStack.push("{");
				}else{
					domainStackjOverflow = false;
				}
				projectStack.push("{");
				//continue;
			}
			
			if ("}".equals(notions.get(i))){
				if (!domainStack.empty()){
					domainStack.pop();
				} else {
					domainStackjOverflow = true;
				}
				projectStack.pop();
				//continue;
				if (domainStack.empty() && domainStackjOverflow==false && list.size() < totalDomainCounts){
					list.add(domain);
				}
				if (domainStack.empty()&&list.size()== totalDomainCounts){					
					return list;
				}				
			}			
			
			if ("domainid".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					Field f = new Field();
					f.setFieldName(notions.get(i+2));
					f.setFieldType(notions.get(i+3));				
					domain.setDomainId(f);
					i += 3;
					continue;
				}
		 }	
			
			if ("domainname".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					Field f = new Field();
					f.setFieldName(notions.get(i+2));
					f.setFieldType("String");					
					domain.setDomainName(f);
					i += 3;
					continue;
				}
		 }
		
			if ("activefield".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					Field f = new Field();
					f.setFieldName(notions.get(i+2));
					f.setFieldType("boolean");					
					domain.setActive(f);
					i += 3;
					continue;
				}
		 }
			
			if ("plural".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					String plural = notions.get(i+2);
					domain.setPlural(plural);
					i += 3;
					continue;
				}
			}
			
			if ("domainlabel".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					String label = notions.get(i+2);
					domain.setLabel(label);
					i += 3;
					continue;
				}
			}
			
			if ("field".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3)) && ";".equals(notions.get(i+4))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i+2))){
						throw new ValidateException("字段"+notions.get(i+2)+"未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i+2),1)){
						throw new ValidateException("字段"+notions.get(i+2)+"第二个字母未使用小写英文字母！");
					}
					Field f = new Field(notions.get(i+2),notions.get(i+3));
					domain.addField(f);	
					i += 3;
				}else if (!isKeyword(notions.get(i+4)) && !";".equals(notions.get(i+4))&&!"}".equals(notions.get(i+4))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i+2))){
						throw new ValidateException("字段"+notions.get(i+2)+"未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i+2),1)){
						throw new ValidateException("字段"+notions.get(i+2)+"第二个字母未使用小写英文字母！");
					}
					Field f = new Field(notions.get(i+2),notions.get(i+3));
					domain.addField(f);	
					
					i += 2;
				}						
				continue;
			}
			
			if ("dropdown".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3)) && ";".equals(notions.get(i+4))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isForbidden(notions.get(i+3))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+3));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+3))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+3));
						throw new ValidateException(info);
					}
					if (!StringUtil.isLowerCaseLetter(notions.get(i+3))){
						throw new ValidateException("字段"+notions.get(i+3)+"未使用小写英文字母开头！");
					}
					if (!StringUtil.isLowerCaseLetterPosition(notions.get(i+3),1)){
						throw new ValidateException("字段"+notions.get(i+3)+"第二个字母未使用小写英文字母！");
					}
					Dropdown dp = new Dropdown(notions.get(i+2));	
					dp.setAliasName(notions.get(i+3));
					dp.setFieldName(dp.getAliasName());
					domain.addField(dp);	
					
					i += 3;
				}						
				continue;
			}
			
			if ("labelfield".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && !isKeyword(notions.get(i+3)) && ";".equals(notions.get(i+4))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					domain.putFieldLabel(notions.get(i+2),notions.get(i+3));
					i += 3;
				}						
				continue;
			}
			
			if ("manytomanyslave".equals(notions.get(i))){
				if (notions.get(i+1).equals(":")&& !isKeyword(notions.get(i+2)) && ";".equals(notions.get(i+3))){
					if (isForbidden(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了被禁止的单词："+notions.get(i+2));
						throw new ValidateException(info);
					}
					if (isSqlKeyword(notions.get(i+2))){
						ValidateInfo info = new ValidateInfo();
						info.addCompileError("使用了SQL关键字："+notions.get(i+2));
						throw new ValidateException(info);
					}
					domain.addManyToManySlaveName(notions.get(i+2));
					i += 2;
				}						
				continue;
			}
			

			if (";".equals(notions.get(i))) continue;
		}				
		ValidateInfo info = new ValidateInfo();
		info.addCompileError("解析域对象错误。");
		throw new ValidateException(info);
	}
	
	public static boolean isKeyword(String notion){
		if ("project".equals(notion)||"prism".equals(notion)||"domain".equals(notion)||"field".equals(notion)
				||"packagetoken".equals(notion)||"plural".equals(notion)||"activefield".equals(notion)
				||"domainname".equals(notion)||"domainid".equals(notion)||"prismdomain".equals(notion)
				||"dbname".equals(notion)|| "emptypassword".equals(notion) || "call".equals(notion) 
				|| "magic".equals(notion) || "domainlabel".equals(notion) || "labelfield".equals(notion)
				|| "manytomanyslave".equals(notion) || "dropdown".equals(notion) )return true;
		else return false;
	}
	
	public static int countDomains(List<String> notions){
		int count = 0;
		for (String s:notions){
			if (s.equals("domain")) count ++;
		}
		return count;
	}
	
	public static int countPrisms(List<String> notions){
		int count = 0;
		for (String s:notions){
			if (s.equals("prism")) count ++;
		}
		return count;
	}
	
	public static boolean containsRoundAndSquareBrackets(String source){
		return source.contains("[") || source.contains("]")|| source.contains("(")|| source.contains(")");
	}
	
	public int countDomain(List<String> notions){
		int count = 0;
		for (String notion:notions){
			if (notion.contains("domain")) count ++;
		}
		return count;
	}
	
	public static Project callMagic(Project project,List<Domain> domainList,DBDefinitionGenerator dbdg, ApplicationContextXml axml) throws Exception{
		Project project2 = new Project(project.getStandardName(),project.getPackageToken(),project.getTechnicalstack(),
		project.getDbUsername(),project.getDbPassword(),project.isEmptypassword(),project.getDbName(),project.getDbType());
		
		decorateDropdowns(domainList);
		if (project.getPackageToken() == null || "".equals(project.getPackageToken())) {		
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("没有设置PackageToken！");
			throw new ValidateException(info);
		} else {			
			String dbPrefix = project.getDbPrefix();
			for (int m=0;m<domainList.size();m++){
				domainList.get(m).setDbPrefix(dbPrefix);
				domainList.get(m).setPackageToken(project.getPackageToken());
			}
		}
		List<Prism> prismList = generatePrismsByDomains(domainList,dbdg,project2.getDbType());
		project2.setPrisms(prismList);
		TreeSet<SpringMVCFacade> myfacades = new TreeSet<SpringMVCFacade>();
		for (Prism p:prismList){
			myfacades.add(p.getFacade());
		}

		project2.setDomains(domainList);
		dbdg.setDomains(domainList);
		
		axml.setDomainList(domainList);
		axml.setDbname(project2.getDbName());
		axml.setDbPassword(project2.getDbPassword());
		axml.setEmptypassword(project2.isEmptypassword());;
		axml.setDbType(project2.getDbType());
		
		axml.setFacades(myfacades);
		if (project.isEmptypassword()) {
			axml.setDbPassword("");
			axml.setEmptypassword(true);
		}
		List<String> packageToScanList = new ArrayList<String>();
		packageToScanList.add(project.getPackageToken()+".domain");
		axml.setPackagesToScanList(packageToScanList);
		axml.setPutInsideSrcAndClasses(true);
		
	
		project2.addDBDefinitionGenerator(dbdg);									
		project2.setPrisms(prismList);
		project2.replaceConfigFile(axml);
		return project2;
	}
	
	public static void decorateDropdowns(List<Domain> domainList) throws ValidateException{
		for (Domain d:domainList){
			for (Field f: d.getFieldsWithoutId()){
				if (f instanceof Dropdown){
					Dropdown dp = (Dropdown)f;
					System.out.println("JerryDebugger:dropdown:"+ dp.getTargetName());
					Domain t = DomainUtil.findDomainInList(domainList, dp.getTargetName());
					dp.decorate(t);
				}
			}
		}
	}
		
	public static boolean locateCallMagic(List<String> notions){
		if (notions.contains("call")&&notions.contains("magic")) return true;
		else return false;
	}
	
	public static List<Prism> generatePrismsByDomains(List<Domain> domainList, DBDefinitionGenerator dbdg) throws Exception{
		return generatePrismsByDomains(domainList,dbdg,"mysql");
	}
	
	public static List<Prism> generatePrismsByDomains(List<Domain> domainList, DBDefinitionGenerator dbdg, String dbType) throws Exception{
		if (dbType==null || "".equals(dbType)||"mysql".equalsIgnoreCase(dbType)){
			List<Prism> prisms = new ArrayList<Prism>();
			Set<Domain> projectDomainSet = new TreeSet<Domain>();
			projectDomainSet.addAll(domainList);
			for (Domain d:domainList){
				d.decorateDomainWithLabels();
				Prism p = new Prism();
				p.setPackageToken(d.getPackageToken());
				p.setStandardName(d.getCapFirstDomainName()+"Prism");
				p.setDomain(d);			
				p.setDbDefinitionGenerator(dbdg);			
				p.setProjectDomains(projectDomainSet);
				p.generatePrismFromDomain();
				prisms.add(p);
			}
			return prisms;
		} else if ("oracle".equalsIgnoreCase(dbType)){
			List<Prism> prisms = new ArrayList<Prism>();
			Set<Domain> projectDomainSet = new TreeSet<Domain>();
			projectDomainSet.addAll(domainList);
			for (Domain d:domainList){
				d.decorateDomainWithLabels();
				OraclePrism p = new OraclePrism();
				p.setPackageToken(d.getPackageToken());
				p.setStandardName(d.getCapFirstDomainName()+"Prism");
				p.setDomain(OracleDomainDecorator.decorateOracleDomain(d));		
				p.setDbDefinitionGenerator(dbdg);			
				p.setProjectDomains(OracleDomainDecorator.decorateOracleDomainSet(projectDomainSet));
				p.generatePrismFromDomain();
				prisms.add(p);
			}
			return prisms;
		} else {
			ValidateInfo info = new ValidateInfo();
			info.addCompileError("未支持的数据库类型。");
			throw new ValidateException(info);
		}
	}
	
	public static ValidateInfo validateDomainsAndPrisms(List<Domain> domains,List<Prism> prisms){
		ValidateInfo validateInfo1 = validateDomains(domains);
		ValidateInfo validateInfo2 = validatePrisms(prisms);
		List<ValidateInfo> vList = new ArrayList<ValidateInfo>();
		vList.add(validateInfo1);
		vList.add(validateInfo2);
		ValidateInfo validateInfo = ValidateInfo.mergeValidateInfo(vList);
		return validateInfo;
	}
	
	public static ValidateInfo validateDomains(List<Domain> domains){
		ValidateInfo validateInfo = new ValidateInfo();
		for (int i=0;i<domains.size();i++){
			if (domains.subList(i+1, domains.size()).contains(domains.get(i))){
				validateInfo.addCompileWarning("域对象"+ domains.get(i).getStandardName()+"重复。");	
			}
		}
		List<ValidateInfo> infos = new ArrayList<ValidateInfo>();
		infos.add(validateInfo);
		for(Domain d:domains){
			ValidateInfo vd = validateDomain(d);
			infos.add(vd);
		}
		return ValidateInfo.mergeValidateInfo(infos);
	}
	
	public static ValidateInfo validatePrisms(List<Prism> prisms){
		ValidateInfo validateInfo = new ValidateInfo();
		List<Prism> targets = new ArrayList<Prism>();
		for (int i=0;i<prisms.size();i++){
			for (int j=0;j<targets.size();j++){
				if (prisms.get(i).getStandardName().equals(targets.get(j).getStandardName())) {
					validateInfo.addCompileWarning("棱柱"+ prisms.get(i).getStandardName()+"重复。");
				}else{
					targets.add(prisms.get(i));
				}
			}
		}
		if (prisms != null){
			for (int i=0;i<prisms.size();i++){
				if (!prisms.get(i).getStandardName().equals(prisms.get(i).getDomain().getStandardName()+"Prism")){
					validateInfo.addCompileWarning("棱柱"+prisms.get(i).getStandardName() + "的域对象"+prisms.get(i).getDomain().getStandardName()+"没有正确设置。");
				}
			}
		}
		return validateInfo;
	}
	
	public static ValidateInfo basicValidateProject(Project project){
		List<Prism> prisms = project.getPrisms();
		List<Domain> domains = project.getDomains();
		return validateDomainsAndPrisms(domains, prisms);
	}
	
	public static ValidateInfo validateDomain(Domain domain){
		ValidateInfo validateInfo = new ValidateInfo();
		if (StringUtil.isBlank(domain.getDomainId())){
			validateInfo.addCompileError("域对象"+domain.getStandardName() + "的主键没有设置。");
		}
		if (StringUtil.isBlank(domain.getDomainName())) {
			validateInfo.addCompileError("域对象"+domain.getStandardName() + "的对象名字没有设置。");
		}
		if (StringUtil.isBlank(domain.getActive())) {
			validateInfo.addCompileError("域对象"+domain.getStandardName() + "的活跃字段没有设置。");
		}
		return validateInfo;
	}
}
